package com.pvdnc.tapkit.chat;

import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;

import androidx.annotation.Nullable;

import com.pvdnc.encrypt.RSAKey;
import com.pvdnc.nsocket.log.SLog;
import com.pvdnc.nsocket.protocol.base.Packet;
import com.pvdnc.tapkit.chat.chat.ChatClient;
import com.pvdnc.tapkit.chat.chat.client.ChatStart;
import com.pvdnc.tapkit.chat.chat.client.ClientInfo;
import com.pvdnc.tapkit.chat.chat.client.ClientReadyReceiver;
import com.pvdnc.tapkit.chat.chat.client.FriendReceiver;
import com.pvdnc.tapkit.chat.chat.client.MessageReceiver;
import com.pvdnc.tapkit.chat.chat.client.ServiceStart;
import com.pvdnc.tapkit.chat.chat.packet.ClientHello;
import com.pvdnc.tapkit.chat.chat.packet.ClientIdle;
import com.pvdnc.tapkit.chat.ui.ChatActivity;
import com.pvdnc.tapkit.chat.ui.friend.FriendActivity;
import com.pvdnc.tapkit.utils.AppStatusReceiver;
import com.pvdnc.tapkit.utils.LocalBroadcast;
import com.pvdnc.tapkit.utils.NotificationUtils;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

public class ChatService extends Service {
    private static final SLog LOG=new SLog(ChatService.class);

    private static final AtomicReference<ChatService> sInstance=new AtomicReference<>();

    public static ChatService get(){
        return sInstance.get();
    }

    public static void start(Context context, ServiceStart serviceStart){
        Intent intent=new Intent(context,ChatService.class);
        intent.putExtra(EXTRA_START_INFO,serviceStart);
        context.startService(intent);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private ChatClient mClient;

    public ChatClient getClient(){
        return mClient;
    }

    private ClientReadyReceiver mReadyReceiver=new ClientReadyReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            login();
            FriendActivity.start(ChatService.this);//启动
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        mNotificationUtils =new NotificationUtils(this);
        //注册广播
        mReadyReceiver.register();
        mFriendReceiver.register();
        mAppStatusReceiver.register();
        mMessageReceiver.register();
        //发布实例
        sInstance.set(this);
        LOG.d("ChatService created");
    }

    private FriendReceiver mFriendReceiver=new FriendReceiver() {
        @Override
        public void onReceive(Context context, Map<String, ClientInfo> friendMap) {
            Set<Map.Entry<String,ClientInfo>> entrySet=friendMap.entrySet();
            for (Map.Entry<String,ClientInfo> entry:entrySet){
                String name=entry.getKey();
                //添加对方PublicKey
                getClient().mKeyManager.putKey(name,entry.getValue().mPublicKey);
            }
        }
    };

    private MessageReceiver mMessageReceiver =new MessageReceiver() {
        @Override
        public void onReceive(Context context, MessageEntity entity) {
            buildNotification(entity);
        }
    };

    public static final String EXTRA_START_INFO ="start_info";

    private ServiceStart mStartInfo;

    public String getName(){
        return mStartInfo.mName;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mStartInfo= (ServiceStart) intent.getSerializableExtra(EXTRA_START_INFO);
        if(mStartInfo==null) {
            LOG.e("start info is null");
            stopSelf();
            return START_STICKY;
        }
        initConnection(false);
        return START_STICKY;
    }

    public void initConnection(boolean closeable){
        if(mClient!=null&& mClient.isRunning()){
            if(!closeable) {
                LOG.e("client is still running");
                return;
            }
            LOG.d("attempt to close old connection");
            mClient.doClose();//先关闭原有连接
        }
        mClient=null;
        LOG.d("start ChatClient on end point:\n\t"+mStartInfo.mEndPoint);
        mClient=new ChatClient(mStartInfo.mEndPoint,mStartInfo.mFullEncryptKey);
        mClient.doConnect();
    }

    public void login() {
        ClientHello clientHello = new ClientHello();
        clientHello.mName = mStartInfo.mName;
        clientHello.mPublicKey=getClient().mKeyManager.mSelfKey.mPublicKey;
        send(clientHello, false);
        LOG.d("login packet of client:"+clientHello.mName+" sent");
    }

    private NotificationUtils mNotificationUtils;

    private void buildNotification(MessageEntity entity){
        if(ChatActivity.mCurrentChat.isReadable()) {
            ChatStart currentChat = ChatActivity.mCurrentChat.getRef();
            if (currentChat != null) {
                if (entity.mName.equals(currentChat.mToName)) {
                    LOG.d("chat:" + entity.mName + " is on activity,there is no need to notify");
                    return;
                }
            }
        }
        Notification.Builder builder=new Notification.Builder(this);
        if(entity.mHeadImg!=null){
            builder.setSmallIcon(R.mipmap.ic_launcher_round);
            builder.setLargeIcon(entity.mHeadImg);
        }
        builder.setContentTitle(entity.mName)
                .setContentText(entity.mContent);
        //发送通知
        mNotificationUtils.notify(builder,entity.mLevel);
    }

    public boolean checkConnection(){
        if(mClient==null)
            return false;
        if(!mClient.isRunning())
            return false;
        try{
            ClientIdle clientIdle=new ClientIdle();
            clientIdle.mName=getName();
            send(clientIdle,true);
            LOG.d("connection seemed to be valid");
            return true;
        }catch (Exception e){
            LOG.e("connection has been closed");
            e.printStackTrace();
            return false;
        }
    }

    private AppStatusReceiver mAppStatusReceiver=new AppStatusReceiver() {
        @Override
        public void onReceive(Context context, int status) {
            switch (status){
                case STATUS_FOREGROUND:{
                    LOG.d("app is going to become foreground");
                    if(!checkConnection()) {
                        LOG.e("connection is lost,trying to re-connect");
                        initConnection(true);
                    }
                    break;
                }
                case STATUS_BACKGROUND:{
                    LOG.d("app is going to become background");
                }
            }
        }
    };

    private RSAKey mSelfKey=new RSAKey(2048);

    public <T extends Packet> void send(T packet,boolean needToWait){
        mClient.send(packet,needToWait);
    }
}
